package com.demo.starter.service.impl;

import com.demo.starter.domain.RemoveRet;
import com.demo.starter.domain.UploadRet;
import com.demo.starter.service.IOSSService;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.BatchStatus;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;

/**
 * 七牛 OSS service
 */
@Log4j2
@Service
public class QiniuOSSServiceImpl implements IOSSService {

    @Value("${oss.qiniu.ak}")
    private String accessKey;
    @Value("${oss.qiniu.sk}")
    private String secretKey;
    @Value("${oss.qiniu.bucket}")
    private String bucket;
    @Value("${oss.qiniu.domain}")
    private String domain;
    @Value("${app.tmpdir}")
    private String tmpDir;

    @Override
    public UploadRet uploadByLocalPath(String localFilePath) {
        UploadRet result = new UploadRet();
        result.setStatus(UploadRet.FAILED);

        //构造一个带指定Zone对象的配置类 华东-Zone.zone0()
        Configuration cfg = new Configuration(Zone.zone0());
        //...其他参数参考类注释
        UploadManager uploadManager = new UploadManager(cfg);
        //默认不指定key的情况下，以文件内容的hash值作为文件名
        String key = null;
        Auth auth = Auth.create(accessKey, secretKey);
        String upToken = auth.uploadToken(bucket);
        try {
            Response response = uploadManager.put(localFilePath, key, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            log.debug("OSS 上传结果：Response={}", response);
            result.setStatus(UploadRet.SUCCESS);
            result.setKey(putRet.key);
            result.setUrl(domain + "/" + putRet.key);
            if (response.isOK()) {
                result.setStatus(1);
            } else {
                result.setStatus(0);
            }
            return result;
        } catch (QiniuException ex) {
            log.error("OSS 上传失败：{}", ex.response);
        }
        return result;
    }

    @Override
    public UploadRet uploadByBytes(byte[] bytes) {
        UploadRet result = new UploadRet();
        result.setStatus(UploadRet.FAILED);

        //构造一个带指定Zone对象的配置类 华东-Zone.zone0()
        Configuration cfg = new Configuration(Zone.zone0());
        //...其他参数参考类注释
        UploadManager uploadManager = new UploadManager(cfg);
        //默认不指定key的情况下，以文件内容的hash值作为文件名
        String key = null;
        Auth auth = Auth.create(accessKey, secretKey);
        String upToken = auth.uploadToken(bucket);
        try {
            Response response = uploadManager.put(bytes, key, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            log.debug("OSS 上传结果：Response={}", response);
            result.setStatus(UploadRet.SUCCESS);
            result.setKey(putRet.key);
            result.setUrl(domain + "/" + putRet.key);
            if (response.isOK()) {
                result.setStatus(1);
            } else {
                result.setStatus(0);
            }
            return result;
        } catch (QiniuException ex) {
            log.error("OSS 上传失败：{}", ex.response);
        }
        return result;
    }

    @Override
    public UploadRet uploadByRemoteURL(String url) throws IOException {
        String originFileName = url.substring(url.lastIndexOf("/") + 1);
        String filePath = download(url, originFileName);
        InputStream inputStream = new FileInputStream(filePath);
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc;
        while ((rc = inputStream.read(buff, 0, 100)) > 0) {
            swapStream.write(buff, 0, rc);
        }
        byte[] bytes = swapStream.toByteArray();
        final UploadRet uploadRet = uploadByBytes(bytes);
        //删除临时文件
        (new File(filePath)).delete();
        return uploadRet;
    }

    private String download(String urlString, String relativeFilePath) throws IOException {
        // 构造URL
        URL url = new URL(urlString);
        // 打开连接
        URLConnection con = url.openConnection();
        //设置请求超时为5s
        con.setConnectTimeout(10000);
        con.setReadTimeout(30000);
        con.setRequestProperty("accept", "*/*");
        con.setRequestProperty("connection", "Keep-Alive");
        con.setRequestProperty("user-agent",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
        // 输入流
        InputStream is = con.getInputStream();

        // 1K的数据缓冲
        byte[] bs = new byte[1024];
        // 读取到的数据长度
        int len;

        // 输出的文件流
        String savePath = tmpDir;
        File sf = new File(savePath);
        if (!sf.exists()) {
            sf.mkdirs();
        }
        String fileNewPath = tmpDir + File.separator + relativeFilePath;
        OutputStream os = new FileOutputStream(fileNewPath);
        // 开始读取
        while ((len = is.read(bs)) != -1) {
            os.write(bs, 0, len);
        }
        // 完毕，关闭所有链接
        os.close();
        is.close();
        return fileNewPath;
    }


    @Override
    public RemoveRet remove(String[] keys) {
        BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
        batchOperations.addDeleteOp(bucket, keys);
        //构造一个带指定Zone对象的配置类 华东-Zone.zone0()
        Configuration cfg = new Configuration(Zone.zone0());
        Auth auth = Auth.create(accessKey, secretKey);
        BucketManager bucketManager = new BucketManager(auth, cfg);
        Response response = null;
        try {
            response = bucketManager.batch(batchOperations);
        } catch (QiniuException e) {
            log.error("OSS 处理失败：{}", e.response);
        }
        BatchStatus[] batchStatusList = new BatchStatus[0];
        try {
            batchStatusList = response.jsonToObject(BatchStatus[].class);
        } catch (QiniuException e) {
            log.error("OSS 处理失败：{}", e.response);
        }

        int resultCode = 1;
        String[] failedKeys = new String[]{};
        for (int i = 0; i < keys.length; i++) {
            BatchStatus status = batchStatusList[i];
            String key = keys[i];
            if (status.code != 200) {
                resultCode = 0;
                ArrayUtils.add(failedKeys, key);
                break;
            }
        }

        RemoveRet ret = new RemoveRet();
        ret.setStatus(resultCode);
        ret.setFailedKeys(failedKeys);
        return ret;
    }

}
